from __future__ import annotations

import os
import socket
import time
from datetime import datetime

import openpyxl
from openpyxl.utils import column_index_from_string
import paramiko
from rich import print
from rich.console import Console

vendor_change = [
    'cisco',
    'huawei',
    'h3c'
]

console = Console()

# 获取当前PC的用户名
pcuser = os.getlogin()
# 存放认证失败的设备信息
switch_with_authentication_issue = []
# 存放网络不通的设备信息
switch_not_reachable = []


class InfoExcel:
    def __init__(self):
        self.excel = openpyxl.load_workbook(
            filename='自动化执行设备清单.xlsx', read_only=True)

    @property
    def list_sheet(self):
        return self.excel['List']

    def _get_list_sheet_value(self, row: int, column: str) -> str:
        return self.list_sheet.cell(row, column_index_from_string(column)).value

    def get_hostname(self, row: int) -> str:
        return self._get_list_sheet_value(row, 'B')

    def get_ip(self, row: int) -> str:
        return self._get_list_sheet_value(row, 'C')

    def get_username(self, row: int) -> str:
        return self._get_list_sheet_value(row, 'D')

    def get_password(self, row: int) -> str:
        return self._get_list_sheet_value(row, 'E')

    def get_vendor(self, row: int) -> str:
        return self._get_list_sheet_value(row, 'F')

    def get_is_enable(self, row: int) -> str:
        return self._get_list_sheet_value(row, 'G')

    def get_enable_pwd(self, row: int) -> str:
        return self._get_list_sheet_value(row, 'H')

    def cli_command(self, vendor: str) -> list:
        vendor = vendor.lower()
        if vendor not in vendor_change:
            print(f'{vendor}不在范围内')
            return []

        cmd_sheet = self.excel[f"{vendor}_commands"]
        cmd_row = cmd_sheet.max_row
        cmd_list = []
        for i in range(1, cmd_row + 1):
            cmd_list.append(cmd_sheet.cell(i, 1).value)

        return cmd_list

    def close(self):
        self.excel.close()


excel = InfoExcel()


def login_get_device(i: int):
    """定义登陆设备执行命令的函数，函数名为login_get_device"""

    device_name = excel.get_hostname(i)
    ip = excel.get_ip(i)
    username = excel.get_username(i)
    password = excel.get_password(i)
    vendor = excel.get_vendor(i)

    print('[bold yellow]开始尝试登录' + device_name + '-' + ip + '[/]')
    ssh_client = paramiko.SSHClient()
    ssh_client.set_missing_host_key_policy(
        paramiko.AutoAddPolicy())  # 自动添加策略，保存服务器的主机名和密钥信息，如果添加不成功，那么不再本地know_hosts文件中记录的主机将无法连接
    ssh_client.connect(hostname=ip, username=username, password=password)
    command = ssh_client.invoke_shell()
    console.rule("[bold red]已经成功登陆网络设备" + ' ' + ip)
    console.rule("[bold red]已获取" + ' ' + ip + '设备的所属厂商，为' + ' ' + vendor)

    if excel.get_is_enable(i):
        # 当需要提权的时候执行
        print(
            f"[bold magenta]执行{excel.get_is_enable(i)} {excel.get_enable_pwd(i)}")
        command.send(excel.get_is_enable(i) + '\n')
        command.send(excel.get_enable_pwd(i) + '\n')
    else:
        print('[bold yellow]该设备无需进行提权操作[/bold yellow]')

    cmds = excel.cli_command(vendor)

    for cmd in cmds:
        # TODO 这里还需要判断命令是否已经执行完毕
        command.send(cmd + '\n')
        time.sleep(5)

    # 抓取回显，放入output变量
    output = command.recv(99999999999)

    date = datetime.now().strftime('%Y-%m-%d')
    back_file_path = os.path.join(
        'C:', os.sep, 'Users', pcuser, 'Documents', date, f"巡检-{ip}.txt")

    # 将回显output写入文件
    with open(back_file_path, 'w+') as f:
        f.write(output)

    # 在交互窗户读取文件
    with open(back_file_path, 'r') as f:
        print(f.read())
        print('[bold green]☺  麻烦使用鼠标滑动一下，查看自动化获取到的信息是否ok[/bold green]')
        os.system("pause")

    # 关闭SSH
    ssh_client.close()
    console.rule("[bold red]执行完毕，已退出登录" + ' ' + ip)
    print('\n\n')


for i in range(2, excel.list_sheet.max_row + 1):
    ip = excel.get_ip(i)
    vendor = excel.get_vendor(i).lower()

    if vendor not in vendor_change:
        print('IP地址为' + ip + '的设备，目前没有规划命令！')
        exit()
    try:
        login_get_device(i)
    except paramiko.ssh_exception.AuthenticationException:
        print(ip + "用户验证失败！")
        switch_with_authentication_issue.append(ip)
    except socket.error:
        print(ip + "目标不可达！")
        switch_not_reachable.append(ip)
# 关闭Execl
excel.close()

print('[bold green] \n 下列网络设备用户验证失败：[/bold green]')
for i in switch_with_authentication_issue:
    print("[italic red]"+i+"[/italic red]")

print('[bold green] \n 下列网络设备不可达：[/bold green]')
for i in switch_not_reachable:
    print("[italic red]"+i+"[/italic red]")
print('\n\n')
os.system("pause")
